#include "error_insert_help.h"

#include <string.h>

#define LIST_MAXSIZE (1024 * 4)

typedef struct 
{
	error_struct data[LIST_MAXSIZE];
	int size;
}error_data_list;

static error_data_list error_list;
static int error_list_initialled;

static void list_initial(error_data_list* list)
{
	list->size = 0;
}

static inline int list_size(error_data_list* list)
{
	return list->size;
}

static int list_full(error_data_list* list)
{
	return list_size(list) == LIST_MAXSIZE;
}

static int list_add_by_round_order(error_data_list* list, error_struct* data)
{
	if(list_full(list))
	{
		return 0;
	}
	int insert_pos = list->size - 1;
	for(;insert_pos >= 0; --insert_pos)
	{
		if(list->data[insert_pos].round <= data->round)
		{
			break;
		}
		memcpy(list->data + insert_pos + 1, list->data + insert_pos, sizeof(error_struct));
	}
	memcpy(list->data + insert_pos + 1, data, sizeof(error_struct));
	++list->size;
	return 1;
}

int add_error_struct(error_struct* error_data)
{
	if(error_list_initialled == 0)
	{
		list_initial(&error_list);
		error_list_initialled = 1;
	}
	if(!list_add_by_round_order(&error_list, error_data))
	{
		return 0;
	}
	return 1;
}

void clear_error_struct()
{
	list_initial(&error_list);
	error_list_initialled = 1;
}

void error_insert_hook_func(byte* left_part, byte* right_part, int round)
{
	int examined_pos = 0;
	for( ;examined_pos < list_size(&error_list); ++examined_pos)
	{
		if(error_list.data[examined_pos].round > round)
			break;
		else if(error_list.data[examined_pos].round == round)
		{
			error_list.data[examined_pos].apply_func(&error_list.data[examined_pos], left_part, right_part);
		}
		else
		{
			//should not reach here!must some error has happened!
		}
	}
}

void xor_error_apply(void* this, byte* left_part, byte* right_part)
{
	error_struct* error_data = (error_struct*)this;
	byte* des_part;
	int real_pos;
	if(error_data->byte_pos < 8)
	{
		des_part = left_part;
		real_pos = error_data->byte_pos;
	}
	else
	{
		des_part = right_part;
		real_pos = error_data->byte_pos % 8;
	}
	des_part[real_pos] ^= error_data->error_byte;
}
